using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;


namespace TacticsPipeline
{
    /// <summary>
    /// This class will be instantiated by the XNA Framework Content Pipeline
    /// to apply custom processing to content data, converting an object of
    /// type TInput to TOutput. The input and output types may be the same if
    /// the processor wishes to alter data without changing its type.
    ///
    /// This should be part of a Content Pipeline Extension Library project.
    ///
    /// TODO: change the ContentProcessor attribute to specify the correct
    /// display name for this processor.
    /// </summary>
    [ContentProcessor(DisplayName = "TerrainProcessor")]
    public class TerrainProcessor : ContentProcessor<Texture2DContent, ModelContent>
    {
        public override ModelContent Process(Texture2DContent input, ContentProcessorContext context)
        {

            MeshBuilder terrainBuilder = MeshBuilder.StartMesh("terrain");

            // Convert the input texture to float format, for ease of processing.
            input.ConvertBitmapType(typeof(PixelBitmapContent<float>));

            PixelBitmapContent<float> heightmap;
            heightmap = (PixelBitmapContent<float>)input.Mipmaps[0];

            int scale = 1;

            for (int y = 0; y < heightmap.Height; ++y)
            {
                for (int x = 0; x < heightmap.Width; ++x)
                {
                    Vector3 position;

                    position.X = scale * x;
                    position.Z = scale * y;

                    position.Y = (heightmap.GetPixel(x, y) - 1) * 30.0f;

                    terrainBuilder.CreatePosition(position);
                }
            }

            BasicMaterialContent terrainMaterial = new BasicMaterialContent();
            terrainMaterial.SpecularColor = new Vector3(.4f, .4f, .4f);

            string directory = Path.GetDirectoryName(input.Identity.SourceFilename);
            string texture = Path.Combine(directory, "grassTX.bmp");
            terrainMaterial.Texture = new ExternalReference<TextureContent>(texture);

            terrainBuilder.SetMaterial(terrainMaterial);

            // Create a vertex channel for holding texture coordinates.
            int texCoordId = terrainBuilder.CreateVertexChannel<Vector2>(
                                            VertexChannelNames.TextureCoordinate(0));

            // Create the individual triangles that make up our terrain.
            for (int y = 0; y < heightmap.Height - 1; ++y)
            {
                for (int x = 0; x < heightmap.Width - 1; ++x)
                {
                    AddVertex(terrainBuilder, texCoordId, heightmap.Width, x, y);
                    AddVertex(terrainBuilder, texCoordId, heightmap.Width, x + 1, y);
                    AddVertex(terrainBuilder, texCoordId, heightmap.Width, x + 1, y + 1);

                    AddVertex(terrainBuilder, texCoordId, heightmap.Width, x, y);
                    AddVertex(terrainBuilder, texCoordId, heightmap.Width, x + 1, y + 1);
                    AddVertex(terrainBuilder, texCoordId, heightmap.Width, x, y + 1);
                }
            }

            MeshContent terrainMesh = terrainBuilder.FinishMesh();

            ModelContent terrainModel = context.Convert<MeshContent, ModelContent>(terrainMesh, "ModelProcessor");

            return terrainModel;
        }

        /// <summary>
        /// Helper for adding a new triangle vertex to a MeshBuilder,
        /// along with an associated texture coordinate value.
        /// </summary>
        void AddVertex(MeshBuilder builder, int texCoordId, int w, int x, int y)
        {
            builder.SetVertexChannelData(texCoordId, new Vector2(x, y) * 0.1f);

            builder.AddTriangleVertex(x + y * w);
        }
    }
}